//
//  PMView.m
//  PezMonkeyTest
//
//  Created by Spence DiNicolantonio on 11/3/09.
//  Copyright 2009 Necrosoft. All rights reserved.
//

#import "PMView.h"
#import <OpenGL/OpenGL.h>
#import <GLUT/GLUT.h>
#import "PezMonkey.h"
#import "PZKeyCodes.h"


static const float framerate = (1.0 / 60.0);

@implementation PMView

@synthesize demo;


#pragma mark -
#pragma mark Init

- (id)initWithCoder:(NSCoder *)coder {
	if (![super initWithCoder:coder])
		return nil;
	
	// initialize PezMonkey
	[PezMonkey initialize];
	
	// set demo
	[self setDemoNumber:5];
	
	// create timer
	[NSTimer scheduledTimerWithTimeInterval:framerate 
									 target:self 
								   selector:@selector(timerFire:) 
								   userInfo:nil 
									repeats:YES];
	return self;
}


#pragma mark -
#pragma mark Timer

- (void)timerFire:(NSTimer *)timer {
//	// calculate time since last fire
//	static NSTimeInterval lastTime = 0.0;
//	if (lastTime == 0.0)
//		lastTime = [NSDate timeIntervalSinceReferenceDate];
//	NSTimeInterval curretentTime = [NSDate timeIntervalSinceReferenceDate];
//	NSTimeInterval deltaT = curretentTime - lastTime;
//	lastTime = curretentTime;
	
//	// update physics engine
//	float stepTime = framerate / (float)stepsPerFrame;
//	for(int i=0; i<stepsPerFrame; i++)
//		[demo.space step:stepTime];
	[demo.space step:framerate];
	
	// request redraw
	[self setNeedsDisplay:YES];
}


#pragma mark -
#pragma mark OpenGL

- (void)prepareOpenGL {
	//NSLog(@"Preparing OpenGL");
	
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glPointSize(3.0);
	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_POINT_SMOOTH);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
	glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
	glLineWidth(2.5f);
}

- (void)reshape {
	//NSLog(@"Reshaping");
	
	// Convert up to window space, which is in pixel units
	NSRect baseRect = [self bounds];//[self convertRectToBase:[self bounds]];
	
	// Now the result is glViewport()-compatible
	glViewport(0, 0, baseRect.size.width, baseRect.size.height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-320.0, 320.0, -240.0, 240.0, -1.0, 1.0);
	glTranslatef(0.5, 0.5, 0.0);
}

- (void)drawRect:(NSRect)rect {
	//NSLog(@"Drawing");
	
	// Clear the background
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	// Reset the coordinate system
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	// Draw
	[demo draw];
	
	// Flush to screen
	glFlush();
	glSwapAPPLE();
}


#pragma mark -
#pragma mark Set Demo

- (void)setDemoNumber:(NSUInteger)demoNumber {
	PMDemo *newDemo;
	switch (demoNumber) {
		case 1:
			// newDemo = [[[Demo1 alloc] init] autorelease];
			break;
		case 2:
			// newDemo = [[[Demo2 alloc] init] autorelease];
			break;
		case 3:
			// newDemo = [[[Demo3 alloc] init] autorelease];
			break;
		case 4:
			// newDemo = [[[Demo4 alloc] init] autorelease];
			break;
		case 5:
			newDemo = [[[Demo5 alloc] init] autorelease];
			break;
		case 6:
			// newDemo = [[[Demo6 alloc] init] autorelease];
			break;
		case 7:
			// newDemo = [[[Demo7 alloc] init] autorelease];
			break;
		default:
			break;
	}
	[self setDemo:newDemo];
}

- (void)setDemo:(PMDemo *)newDemo {
	if ([demo isEqual:newDemo])
		return;
	
	[demo release];
	demo = [newDemo retain];
	[demo initDemo];
}


#pragma mark -
#pragma mark Keyboard / Mouse

- (BOOL)acceptsFirstResponder {
	return YES;
}

- (void)keyDown:(NSEvent *)theEvent {
	NSUInteger demoNumber = [[theEvent characters] intValue];
	[self setDemoNumber:demoNumber];
}

- (void)mouseDown:(NSEvent *)theEvent {
	PMVect point = [self mouseToSpace:[theEvent locationInWindow]];
	point.y *= -1;
	for (PMShape *shape in [demo.space shapes])
		if ([shape isPointInShape:point])
			[demo.space removeShapeAndBody:shape];
}

- (PMVect)mouseToSpace:(NSPoint)point {
	GLdouble model[16];
	glGetDoublev(GL_MODELVIEW_MATRIX, model);
	
	GLdouble proj[16];
	glGetDoublev(GL_PROJECTION_MATRIX, proj);
	
	GLint view[4];
	glGetIntegerv(GL_VIEWPORT, view);
	
	GLdouble mx, my, mz;
	gluUnProject(point.x, self.bounds.size.height - point.y, 0.0f, model, proj, view, &mx, &my, &mz);
	
	return PMVectMake(mx, my);
}
	

@end
